package defectsim;

import repast.simphony.context.Context;
import repast.simphony.space.continuous.NdPoint;
import repast.simphony.space.grid.Grid;
import repast.simphony.util.ContextUtils;
import repast.simphony.valueLayer.GridValueLayer;

public class DefectDomain {


	/**
	 * @author Altug Uzunali
	 * 
	 * The area around a defect within its perception radius is denoted as the "Defect Domain"
	 * For simplicity defect domain is considered as a circle with the defect in its center
	 */

	static SimEnvironment env = SimEnvironment.getInstance();
	private static GridValueLayer elasticField = null;
	private static GridValueLayer energyField = null;

	@SuppressWarnings("unchecked")
	public static void updateDefectDomain(DefectAgent da){
		int x;
		int y;

		Grid grid = (Grid)ContextUtils.getContext(da).getProjection("Simple Grid");

		int point[] = grid.getLocation(da).toIntArray(null);
		x = point[0];
		y = point[1];

		calculateDefectDomain(da, x, y);
	}
	
	public static void zeroDomains(){
		Context<DefectAgent> context = env.getContext();
		elasticField = (GridValueLayer)context.getValueLayer("Elastic Field");
		fillZero(elasticField);
		
		energyField = (GridValueLayer)context.getValueLayer("Energy Field");
		fillZero(energyField);
	}

	private static void calculateDefectDomain(DefectAgent da, int x0, int y0){
		
		int radius = (int) (env.getMaxCutOffRadius() * env.getGridSize() / env.getSpaceLength());

		for (int i = 1; i <= radius; i++) {


			int f = 1 - i;
			int ddF_x = 1;
			int ddF_y = -2 * i;
			int x = 0;
			int y = i;

			setElasticStress(elasticField, da, x0, y0, x0, y0 + i);
			setElasticStress(elasticField, da, x0, y0, x0, y0 - i);
			setElasticStress(elasticField, da, x0, y0, x0 + i, y0);
			setElasticStress(elasticField, da, x0, y0, x0 - i, y0);
			
			setEnergy(energyField, da, x0, y0, x0, y0 + i);
			setEnergy(energyField, da, x0, y0, x0, y0 - i);
			setEnergy(energyField, da, x0, y0, x0 + i, y0);
			setEnergy(energyField, da, x0, y0, x0 - i, y0);

			while(x < y)
			{
				if(f >= 0) 
				{
					y--;
					ddF_y += 2;
					f += ddF_y;
				}
				x++;
				ddF_x += 2;
				f += ddF_x;    
				setElasticStress(elasticField, da, x0, y0, x0 + x, y0 + y);
				setElasticStress(elasticField, da, x0, y0, x0 - x, y0 + y);
				setElasticStress(elasticField, da, x0, y0, x0 + x, y0 - y);
				setElasticStress(elasticField, da, x0, y0, x0 - x, y0 - y);
				setElasticStress(elasticField, da, x0, y0, x0 + y, y0 + x);
				setElasticStress(elasticField, da, x0, y0, x0 - y, y0 + x);
				setElasticStress(elasticField, da, x0, y0, x0 + y, y0 - x);
				setElasticStress(elasticField, da, x0, y0, x0 - y, y0 - x);
				
				setEnergy(energyField, da, x0, y0, x0 + x, y0 + y);
				setEnergy(energyField, da, x0, y0, x0 - x, y0 + y);
				setEnergy(energyField, da, x0, y0, x0 + x, y0 - y);
				setEnergy(energyField, da, x0, y0, x0 - x, y0 - y);
				setEnergy(energyField, da, x0, y0, x0 + y, y0 + x);
				setEnergy(energyField, da, x0, y0, x0 - y, y0 + x);
				setEnergy(energyField, da, x0, y0, x0 + y, y0 - x);
				setEnergy(energyField, da, x0, y0, x0 - y, y0 - x);

			}

		}

	}

	private static void setElasticStress(GridValueLayer vl, DefectAgent da, int x0, int y0, int x1, int y1){
		double l = Util.calculateMICDistance(new NdPoint(x0, y0), new NdPoint(x1, y1), env.getSpaceLength()); 
		double angle = Util.calculateMICAngle(new NdPoint(x0, y0), new NdPoint(x1, y1), env.getSpaceLength());
//		if (l != 0.0){
////			double f = Util.calculateGlideStressInCylindiricalCoordinates(new NdPoint(x0, y0), new NdPoint(x1, y1), 
////					((Dislocation)da).getUnitBurgersVector(), env.getCurrentMaterial(), env.getSpaceLength());
//			vl.set(vl.get(x1, y1) + f, x1, y1);
//		}
	}
	
	private static void setEnergy(GridValueLayer vl, DefectAgent da, int x0, int y0, int x1, int y1){
		Material mat = env.getCurrentMaterial();
		double C = 4 * Math.PI * (1 - mat.getPoissonRatio());
		double l = Util.calculateMICDistance(new NdPoint(x0, y0), new NdPoint(x1, y1), env.getSpaceLength()); 
//		double angle = Util.calculateMICAngle(new NdPoint(x0, y0), new NdPoint(x1, y1), env.getSpaceLength());
		double bgVec = ((Dislocation)da).getUnitBurgersVector() * mat.getBurgersVector();
		double A = (mat.getShearModulus() * bgVec * bgVec) / C;
		double e = A * Math.log(l * 1000 / mat.getBurgersVector());
			vl.set(vl.get(x1, y1) + e, x1, y1);
	}

	private static void fillZero(GridValueLayer vl){
		for (int i = 0; i < vl.getDimensions().getWidth(); i++) 
			for (int j = 0; j < vl.getDimensions().getHeight(); j++)
				vl.set(0.0, i, j);
	}
}
